home *** CD-ROM | disk | FTP | other *** search
/ Aminet 52 / Aminet 52 (2002)(GTI - Schatztruhe)[!][Dec 2002].iso / Aminet / dev / gg / ncurses-5.3.lha / ncurses-5.3 / progs / tset.c < prev   
C/C++ Source or Header  |  2002-10-24  |  30KB  |  1,212 lines

  1. /****************************************************************************
  2.  * Copyright (c) 1998-2001,2002 Free Software Foundation, Inc.              *
  3.  *                                                                          *
  4.  * Permission is hereby granted, free of charge, to any person obtaining a  *
  5.  * copy of this software and associated documentation files (the            *
  6.  * "Software"), to deal in the Software without restriction, including      *
  7.  * without limitation the rights to use, copy, modify, merge, publish,      *
  8.  * distribute, distribute with modifications, sublicense, and/or sell       *
  9.  * copies of the Software, and to permit persons to whom the Software is    *
  10.  * furnished to do so, subject to the following conditions:                 *
  11.  *                                                                          *
  12.  * The above copyright notice and this permission notice shall be included  *
  13.  * in all copies or substantial portions of the Software.                   *
  14.  *                                                                          *
  15.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
  16.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
  17.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
  18.  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
  19.  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
  20.  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
  21.  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
  22.  *                                                                          *
  23.  * Except as contained in this notice, the name(s) of the above copyright   *
  24.  * holders shall not be used in advertising or otherwise to promote the     *
  25.  * sale, use or other dealings in this Software without prior written       *
  26.  * authorization.                                                           *
  27.  ****************************************************************************/
  28.  
  29. /****************************************************************************
  30.  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
  31.  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
  32.  ****************************************************************************/
  33.  
  34. /*
  35.  * tset.c - terminal initialization utility
  36.  *
  37.  * This code was mostly swiped from 4.4BSD tset, with some obsolescent
  38.  * cruft removed and substantial portions rewritten.  A Regents of the
  39.  * University of California copyright applies to some portions of the
  40.  * code, and is reproduced below:
  41.  */
  42. /*-
  43.  * Copyright (c) 1980, 1991, 1993
  44.  *    The Regents of the University of California.  All rights reserved.
  45.  *
  46.  * Redistribution and use in source and binary forms, with or without
  47.  * modification, are permitted provided that the following conditions
  48.  * are met:
  49.  * 1. Redistributions of source code must retain the above copyright
  50.  *    notice, this list of conditions and the following disclaimer.
  51.  * 2. Redistributions in binary form must reproduce the above copyright
  52.  *    notice, this list of conditions and the following disclaimer in the
  53.  *    documentation and/or other materials provided with the distribution.
  54.  * 3. All advertising materials mentioning features or use of this software
  55.  *    must display the following acknowledgement:
  56.  *    This product includes software developed by the University of
  57.  *    California, Berkeley and its contributors.
  58.  * 4. Neither the name of the University nor the names of its contributors
  59.  *    may be used to endorse or promote products derived from this software
  60.  *    without specific prior written permission.
  61.  *
  62.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  63.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  64.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  65.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  66.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  67.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  68.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  69.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  70.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  71.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  72.  * SUCH DAMAGE.
  73.  */
  74.  
  75. #define __INTERNAL_CAPS_VISIBLE    /* we need to see has_hardware_tabs */
  76. #include <progs.priv.h>
  77.  
  78. #include <errno.h>
  79. #include <stdio.h>
  80. #include <termcap.h>
  81. #include <fcntl.h>
  82.  
  83. #if HAVE_GETTTYNAM && HAVE_TTYENT_H
  84. #include <ttyent.h>
  85. #endif
  86. #ifdef NeXT
  87. char *ttyname(int fd);
  88. #endif
  89.  
  90. /* this is just to stifle a missing-prototype warning */
  91. #ifdef linux
  92. # include <sys/ioctl.h>
  93. #endif
  94.  
  95. #if NEED_PTEM_H
  96. /* they neglected to define struct winsize in termios.h -- it's only
  97.    in termio.h    */
  98. #include <sys/stream.h>
  99. #include <sys/ptem.h>
  100. #endif
  101.  
  102. #include <curses.h>        /* for bool typedef */
  103. #include <dump_entry.h>
  104. #include <transform.h>
  105.  
  106. MODULE_ID("$Id: tset.c,v 0.53 2002/08/24 23:18:16 tom Exp $")
  107.  
  108. extern char **environ;
  109.  
  110. #undef CTRL
  111. #define CTRL(x)    ((x) & 0x1f)
  112.  
  113. const char *_nc_progname = "tset";
  114.  
  115. static TTY mode, oldmode, original;
  116.  
  117. static bool can_restore = FALSE;
  118. static bool isreset = FALSE;    /* invoked as reset */
  119. static int terasechar = -1;    /* new erase character */
  120. static int intrchar = -1;    /* new interrupt character */
  121. static int tkillchar = -1;    /* new kill character */
  122. static int tlines, tcolumns;    /* window size */
  123.  
  124. #define LOWERCASE(c) ((isalpha(UChar(c)) && isupper(UChar(c))) ? tolower(UChar(c)) : (c))
  125.  
  126. static int
  127. CaselessCmp(const char *a, const char *b)
  128. {                /* strcasecmp isn't portable */
  129.     while (*a && *b) {
  130.     int cmp = LOWERCASE(*a) - LOWERCASE(*b);
  131.     if (cmp != 0)
  132.         break;
  133.     a++, b++;
  134.     }
  135.     return LOWERCASE(*a) - LOWERCASE(*b);
  136. }
  137.  
  138. static void
  139. exit_error(void)
  140. {
  141.     if (can_restore)
  142.     SET_TTY(STDERR_FILENO, &original);
  143.     (void) fprintf(stderr, "\n");
  144.     fflush(stderr);
  145.     exit(EXIT_FAILURE);
  146.     /* NOTREACHED */
  147. }
  148.  
  149. static void
  150. err(const char *fmt,...)
  151. {
  152.     va_list ap;
  153.     va_start(ap, fmt);
  154.     (void) fprintf(stderr, "tset: ");
  155.     (void) vfprintf(stderr, fmt, ap);
  156.     va_end(ap);
  157.     exit_error();
  158.     /* NOTREACHED */
  159. }
  160.  
  161. static void
  162. failed(const char *msg)
  163. {
  164.     char temp[BUFSIZ];
  165.     perror(strncat(strcpy(temp, "tset: "), msg, sizeof(temp) - 10));
  166.     exit_error();
  167.     /* NOTREACHED */
  168. }
  169.  
  170. static void
  171. cat(char *file)
  172. {
  173.     FILE *fp;
  174.     size_t nr;
  175.     char buf[BUFSIZ];
  176.  
  177.     if ((fp = fopen(file, "r")) == 0)
  178.     failed(file);
  179.  
  180.     while ((nr = fread(buf, sizeof(char), sizeof(buf), fp)) != 0)
  181.     if (fwrite(buf, sizeof(char), nr, stderr) != nr)
  182.           failed("write to stderr");
  183.     fclose(fp);
  184. }
  185.  
  186. static int
  187. outc(int c)
  188. {
  189.     return putc(c, stderr);
  190. }
  191.  
  192. /* Prompt the user for a terminal type. */
  193. static const char *
  194. askuser(const char *dflt)
  195. {
  196.     static char answer[256];
  197.     char *p;
  198.  
  199.     /* We can get recalled; if so, don't continue uselessly. */
  200.     clearerr(stdin);
  201.     if (feof(stdin) || ferror(stdin)) {
  202.     (void) fprintf(stderr, "\n");
  203.     exit_error();
  204.     /* NOTREACHED */
  205.     }
  206.     for (;;) {
  207.     if (dflt)
  208.         (void) fprintf(stderr, "Terminal type? [%s] ", dflt);
  209.     else
  210.         (void) fprintf(stderr, "Terminal type? ");
  211.     (void) fflush(stderr);
  212.  
  213.     if (fgets(answer, sizeof(answer), stdin) == 0) {
  214.         if (dflt == 0) {
  215.         exit_error();
  216.         /* NOTREACHED */
  217.         }
  218.         return (dflt);
  219.     }
  220.  
  221.     if ((p = strchr(answer, '\n')) != 0)
  222.         *p = '\0';
  223.     if (answer[0])
  224.         return (answer);
  225.     if (dflt != 0)
  226.         return (dflt);
  227.     }
  228. }
  229.  
  230. /**************************************************************************
  231.  *
  232.  * Mapping logic begins here
  233.  *
  234.  **************************************************************************/
  235.  
  236. /* Baud rate conditionals for mapping. */
  237. #define    GT        0x01
  238. #define    EQ        0x02
  239. #define    LT        0x04
  240. #define    NOT        0x08
  241. #define    GE        (GT | EQ)
  242. #define    LE        (LT | EQ)
  243.  
  244. typedef struct map {
  245.     struct map *next;        /* Linked list of maps. */
  246.     const char *porttype;    /* Port type, or "" for any. */
  247.     const char *type;        /* Terminal type to select. */
  248.     int conditional;        /* Baud rate conditionals bitmask. */
  249.     int speed;            /* Baud rate to compare against. */
  250. } MAP;
  251.  
  252. static MAP *cur, *maplist;
  253.  
  254. typedef struct speeds {
  255.     const char *string;
  256.     int speed;
  257. } SPEEDS;
  258.  
  259. static const SPEEDS speeds[] =
  260. {
  261.     {"0", B0},
  262.     {"50", B50},
  263.     {"75", B75},
  264.     {"110", B110},
  265.     {"134", B134},
  266.     {"134.5", B134},
  267.     {"150", B150},
  268.     {"200", B200},
  269.     {"300", B300},
  270.     {"600", B600},
  271.     {"1200", B1200},
  272.     {"1800", B1800},
  273.     {"2400", B2400},
  274.     {"4800", B4800},
  275.     {"9600", B9600},
  276.     /* sgttyb may define up to this point */
  277. #ifdef B19200
  278.     {"19200", B19200},
  279. #endif
  280. #ifdef B38400
  281.     {"38400", B38400},
  282. #endif
  283. #ifdef B19200
  284.     {"19200", B19200},
  285. #endif
  286. #ifdef B38400
  287.     {"38400", B38400},
  288. #endif
  289. #ifdef B19200
  290.     {"19200", B19200},
  291. #else
  292. #ifdef EXTA
  293.     {"19200", EXTA},
  294. #endif
  295. #endif
  296. #ifdef B38400
  297.     {"38400", B38400},
  298. #else
  299. #ifdef EXTB
  300.     {"38400", EXTB},
  301. #endif
  302. #endif
  303. #ifdef B57600
  304.     {"57600", B57600},
  305. #endif
  306. #ifdef B115200
  307.     {"115200", B115200},
  308. #endif
  309. #ifdef B230400
  310.     {"230400", B230400},
  311. #endif
  312. #ifdef B460800
  313.     {"460800", B460800},
  314. #endif
  315.     {(char *) 0, 0}
  316. };
  317.  
  318. static int
  319. tbaudrate(char *rate)
  320. {
  321.     const SPEEDS *sp;
  322.     int found = FALSE;
  323.  
  324.     /* The baudrate number can be preceded by a 'B', which is ignored. */
  325.     if (*rate == 'B')
  326.     ++rate;
  327.  
  328.     for (sp = speeds; sp->string; ++sp) {
  329.     if (!CaselessCmp(rate, sp->string)) {
  330.         found = TRUE;
  331.         break;
  332.     }
  333.     }
  334.     if (!found)
  335.     err("unknown baud rate %s", rate);
  336.     return (sp->speed);
  337. }
  338.  
  339. /*
  340.  * Syntax for -m:
  341.  * [port-type][test baudrate]:terminal-type
  342.  * The baud rate tests are: >, <, @, =, !
  343.  */
  344. static void
  345. add_mapping(const char *port, char *arg)
  346. {
  347.     MAP *mapp;
  348.     char *copy, *p;
  349.     const char *termp;
  350.     char *base = 0;
  351.  
  352.     copy = strdup(arg);
  353.     mapp = malloc(sizeof(MAP));
  354.     if (copy == 0 || mapp == 0)
  355.     failed("malloc");
  356.     mapp->next = 0;
  357.     if (maplist == 0)
  358.     cur = maplist = mapp;
  359.     else {
  360.     cur->next = mapp;
  361.     cur = mapp;
  362.     }
  363.  
  364.     mapp->porttype = arg;
  365.     mapp->conditional = 0;
  366.  
  367.     arg = strpbrk(arg, "><@=!:");
  368.  
  369.     if (arg == 0) {        /* [?]term */
  370.     mapp->type = mapp->porttype;
  371.     mapp->porttype = 0;
  372.     goto done;
  373.     }
  374.  
  375.     if (arg == mapp->porttype)    /* [><@=! baud]:term */
  376.     termp = mapp->porttype = 0;
  377.     else
  378.     termp = base = arg;
  379.  
  380.     for (;; ++arg) {        /* Optional conditionals. */
  381.     switch (*arg) {
  382.     case '<':
  383.         if (mapp->conditional & GT)
  384.         goto badmopt;
  385.         mapp->conditional |= LT;
  386.         break;
  387.     case '>':
  388.         if (mapp->conditional & LT)
  389.         goto badmopt;
  390.         mapp->conditional |= GT;
  391.         break;
  392.     case '@':
  393.     case '=':        /* Not documented. */
  394.         mapp->conditional |= EQ;
  395.         break;
  396.     case '!':
  397.         mapp->conditional |= NOT;
  398.         break;
  399.     default:
  400.         goto next;
  401.     }
  402.     }
  403.  
  404.   next:
  405.     if (*arg == ':') {
  406.     if (mapp->conditional)
  407.         goto badmopt;
  408.     ++arg;
  409.     } else {            /* Optional baudrate. */
  410.     arg = strchr(p = arg, ':');
  411.     if (arg == 0)
  412.         goto badmopt;
  413.     *arg++ = '\0';
  414.     mapp->speed = tbaudrate(p);
  415.     }
  416.  
  417.     if (arg == (char *) 0)    /* Non-optional type. */
  418.     goto badmopt;
  419.  
  420.     mapp->type = arg;
  421.  
  422.     /* Terminate porttype, if specified. */
  423.     if (termp != 0)
  424.     *base = '\0';
  425.  
  426.     /* If a NOT conditional, reverse the test. */
  427.     if (mapp->conditional & NOT)
  428.     mapp->conditional = ~mapp->conditional & (EQ | GT | LT);
  429.  
  430.     /* If user specified a port with an option flag, set it. */
  431.   done:if (port) {
  432.     if (mapp->porttype)
  433.       badmopt:err("illegal -m option format: %s", copy);
  434.     mapp->porttype = port;
  435.     }
  436. #ifdef MAPDEBUG
  437.     (void) printf("port: %s\n", mapp->porttype ? mapp->porttype : "ANY");
  438.     (void) printf("type: %s\n", mapp->type);
  439.     (void) printf("conditional: ");
  440.     p = "";
  441.     if (mapp->conditional & GT) {
  442.     (void) printf("GT");
  443.     p = "/";
  444.     }
  445.     if (mapp->conditional & EQ) {
  446.     (void) printf("%sEQ", p);
  447.     p = "/";
  448.     }
  449.     if (mapp->conditional & LT)
  450.     (void) printf("%sLT", p);
  451.     (void) printf("\nspeed: %d\n", mapp->speed);
  452. #endif
  453. }
  454.  
  455. /*
  456.  * Return the type of terminal to use for a port of type 'type', as specified
  457.  * by the first applicable mapping in 'map'.  If no mappings apply, return
  458.  * 'type'.
  459.  */
  460. static const char *
  461. mapped(const char *type)
  462. {
  463.     MAP *mapp;
  464.     int match;
  465.  
  466.     for (mapp = maplist; mapp; mapp = mapp->next)
  467.     if (mapp->porttype == 0 || !strcmp(mapp->porttype, type)) {
  468.         switch (mapp->conditional) {
  469.         case 0:        /* No test specified. */
  470.         match = TRUE;
  471.         break;
  472.         case EQ:
  473.         match = (ospeed == mapp->speed);
  474.         break;
  475.         case GE:
  476.         match = (ospeed >= mapp->speed);
  477.         break;
  478.         case GT:
  479.         match = (ospeed > mapp->speed);
  480.         break;
  481.         case LE:
  482.         match = (ospeed <= mapp->speed);
  483.         break;
  484.         case LT:
  485.         match = (ospeed < mapp->speed);
  486.         break;
  487.         default:
  488.         match = FALSE;
  489.         }
  490.         if (match)
  491.         return (mapp->type);
  492.     }
  493.     /* No match found; return given type. */
  494.     return (type);
  495. }
  496.  
  497. /**************************************************************************
  498.  *
  499.  * Entry fetching
  500.  *
  501.  **************************************************************************/
  502.  
  503. /*
  504.  * Figure out what kind of terminal we're dealing with, and then read in
  505.  * its termcap entry.
  506.  */
  507. static const char *
  508. get_termcap_entry(char *userarg)
  509. {
  510.     int errret;
  511.     char *p;
  512.     const char *ttype;
  513. #if HAVE_GETTTYNAM
  514.     struct ttyent *t;
  515. #else
  516.     FILE *fp;
  517. #endif
  518.     char *ttypath;
  519.  
  520.     if (userarg) {
  521.     ttype = userarg;
  522.     goto found;
  523.     }
  524.  
  525.     /* Try the environment. */
  526.     if ((ttype = getenv("TERM")) != 0)
  527.     goto map;
  528.  
  529.     if ((ttypath = ttyname(STDERR_FILENO)) != 0) {
  530.     p = _nc_basename(ttypath);
  531. #if HAVE_GETTTYNAM
  532.     /*
  533.      * We have the 4.3BSD library call getttynam(3); that means
  534.      * there's an /etc/ttys to look up device-to-type mappings in.
  535.      * Try ttyname(3); check for dialup or other mapping.
  536.      */
  537.     if ((t = getttynam(p))) {
  538.         ttype = t->ty_type;
  539.         goto map;
  540.     }
  541. #else
  542.     if ((fp = fopen("/etc/ttytype", "r")) != 0
  543.         || (fp = fopen("/etc/ttys", "r")) != 0) {
  544.         char buffer[BUFSIZ];
  545.         char *s, *t, *d;
  546.  
  547.         while (fgets(buffer, sizeof(buffer) - 1, fp) != 0) {
  548.         for (s = buffer, t = d = 0; *s; s++) {
  549.             if (isspace(UChar(*s)))
  550.             *s = '\0';
  551.             else if (t == 0)
  552.             t = s;
  553.             else if (d == 0 && s != buffer && s[-1] == '\0')
  554.             d = s;
  555.         }
  556.         if (t != 0 && d != 0 && !strcmp(d, p)) {
  557.             ttype = strdup(t);
  558.             fclose(fp);
  559.             goto map;
  560.         }
  561.         }
  562.         fclose(fp);
  563.     }
  564. #endif /* HAVE_GETTTYNAM */
  565.     }
  566.  
  567.     /* If still undefined, use "unknown". */
  568.     ttype = "unknown";
  569.  
  570.   map:ttype = mapped(ttype);
  571.  
  572.     /*
  573.      * If not a path, remove TERMCAP from the environment so we get a
  574.      * real entry from /etc/termcap.  This prevents us from being fooled
  575.      * by out of date stuff in the environment.
  576.      */
  577.   found:if ((p = getenv("TERMCAP")) != 0 && *p != '/') {
  578.     /* 'unsetenv("TERMCAP")' is not portable.
  579.      * The 'environ' array is better.
  580.      */
  581.     int n;
  582.     for (n = 0; environ[n] != 0; n++) {
  583.         if (!strncmp("TERMCAP=", environ[n], 8)) {
  584.         while ((environ[n] = environ[n + 1]) != 0) {
  585.             n++;
  586.         }
  587.         break;
  588.         }
  589.     }
  590.     }
  591.  
  592.     /*
  593.      * ttype now contains a pointer to the type of the terminal.
  594.      * If the first character is '?', ask the user.
  595.      */
  596.     if (ttype[0] == '?') {
  597.     if (ttype[1] != '\0')
  598.         ttype = askuser(ttype + 1);
  599.     else
  600.         ttype = askuser(0);
  601.     }
  602.     /* Find the terminfo entry.  If it doesn't exist, ask the user. */
  603.     while (setupterm((NCURSES_CONST char *) ttype, STDOUT_FILENO, &errret)
  604.        != OK) {
  605.     if (errret == 0) {
  606.         (void) fprintf(stderr, "tset: unknown terminal type %s\n",
  607.                ttype);
  608.         ttype = 0;
  609.     } else {
  610.         (void) fprintf(stderr,
  611.                "tset: can't initialize terminal type %s (error %d)\n",
  612.                ttype, errret);
  613.         ttype = 0;
  614.     }
  615.     ttype = askuser(ttype);
  616.     }
  617. #if BROKEN_LINKER
  618.     tgetflag("am");        /* force lib_termcap.o to be linked for 'ospeed' */
  619. #endif
  620.     return (ttype);
  621. }
  622.  
  623. /**************************************************************************
  624.  *
  625.  * Mode-setting logic
  626.  *
  627.  **************************************************************************/
  628.  
  629. /* some BSD systems have these built in, some systems are missing
  630.  * one or more definitions. The safest solution is to override.
  631.  */
  632. #undef CEOF
  633. #undef CERASE
  634. #undef CINTR
  635. #undef CKILL
  636. #undef CLNEXT
  637. #undef CRPRNT
  638. #undef CQUIT
  639. #undef CSTART
  640. #undef CSTOP
  641. #undef CSUSP
  642.  
  643. /* control-character defaults */
  644. #define CEOF    CTRL('D')
  645. #define CERASE    CTRL('H')
  646. #define CINTR    127        /* ^? */
  647. #define CKILL    CTRL('U')
  648. #define CLNEXT  CTRL('v')
  649. #define CRPRNT  CTRL('r')
  650. #define CQUIT    CTRL('\\')
  651. #define CSTART    CTRL('Q')
  652. #define CSTOP    CTRL('S')
  653. #define CSUSP    CTRL('Z')
  654.  
  655. #define    CHK(val, dft)    ((int)val <= 0 ? dft : val)
  656.  
  657. static bool set_tabs(void);
  658.  
  659. /*
  660.  * Reset the terminal mode bits to a sensible state.  Very useful after
  661.  * a child program dies in raw mode.
  662.  */
  663. static void
  664. reset_mode(void)
  665. {
  666. #ifdef TERMIOS
  667.     tcgetattr(STDERR_FILENO, &mode);
  668. #else
  669.     stty(STDERR_FILENO, &mode);
  670. #endif
  671.  
  672. #ifdef TERMIOS
  673. #if defined(VDISCARD) && defined(CDISCARD)
  674.     mode.c_cc[VDISCARD] = CHK(mode.c_cc[VDISCARD], CDISCARD);
  675. #endif
  676.     mode.c_cc[VEOF] = CHK(mode.c_cc[VEOF], CEOF);
  677.     mode.c_cc[VERASE] = CHK(mode.c_cc[VERASE], CERASE);
  678. #if defined(VFLUSH) && defined(CFLUSH)
  679.     mode.c_cc[VFLUSH] = CHK(mode.c_cc[VFLUSH], CFLUSH);
  680. #endif
  681.     mode.c_cc[VINTR] = CHK(mode.c_cc[VINTR], CINTR);
  682.     mode.c_cc[VKILL] = CHK(mode.c_cc[VKILL], CKILL);
  683. #if defined(VLNEXT) && defined(CLNEXT)
  684.     mode.c_cc[VLNEXT] = CHK(mode.c_cc[VLNEXT], CLNEXT);
  685. #endif
  686.     mode.c_cc[VQUIT] = CHK(mode.c_cc[VQUIT], CQUIT);
  687. #if defined(VREPRINT) && defined(CRPRNT)
  688.     mode.c_cc[VREPRINT] = CHK(mode.c_cc[VREPRINT], CRPRNT);
  689. #endif
  690. #if defined(VSTART) && defined(CSTART)
  691.     mode.c_cc[VSTART] = CHK(mode.c_cc[VSTART], CSTART);
  692. #endif
  693. #if defined(VSTOP) && defined(CSTOP)
  694.     mode.c_cc[VSTOP] = CHK(mode.c_cc[VSTOP], CSTOP);
  695. #endif
  696. #if defined(VSUSP) && defined(CSUSP)
  697.     mode.c_cc[VSUSP] = CHK(mode.c_cc[VSUSP], CSUSP);
  698. #endif
  699. #if defined(VWERASE) && defined(CWERASE)
  700.     mode.c_cc[VWERASE] = CHK(mode.c_cc[VWERASE], CWERASE);
  701. #endif
  702.  
  703.     mode.c_iflag &= ~(IGNBRK | PARMRK | INPCK | ISTRIP | INLCR | IGNCR
  704. #ifdef IUCLC
  705.               | IUCLC
  706. #endif
  707. #ifdef IXANY
  708.               | IXANY
  709. #endif
  710.               | IXOFF);
  711.  
  712.     mode.c_iflag |= (BRKINT | IGNPAR | ICRNL | IXON
  713. #ifdef IMAXBEL
  714.              | IMAXBEL
  715. #endif
  716.     );
  717.  
  718.     mode.c_oflag &= ~(0
  719. #ifdef OLCUC
  720.               | OLCUC
  721. #endif
  722. #ifdef OCRNL
  723.               | OCRNL
  724. #endif
  725. #ifdef ONOCR
  726.               | ONOCR
  727. #endif
  728. #ifdef ONLRET
  729.               | ONLRET
  730. #endif
  731. #ifdef OFILL
  732.               | OFILL
  733. #endif
  734. #ifdef OFDEL
  735.               | OFDEL
  736. #endif
  737. #ifdef NLDLY
  738.               | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY
  739. #endif
  740.     );
  741.  
  742.     mode.c_oflag |= (OPOST
  743. #ifdef ONLCR
  744.              | ONLCR
  745. #endif
  746.     );
  747.  
  748.     mode.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD | CLOCAL);
  749.     mode.c_cflag |= (CS8 | CREAD);
  750.     mode.c_lflag &= ~(ECHONL | NOFLSH
  751. #ifdef TOSTOP
  752.               | TOSTOP
  753. #endif
  754. #ifdef ECHOPTR
  755.               | ECHOPRT
  756. #endif
  757. #ifdef XCASE
  758.               | XCASE
  759. #endif
  760.     );
  761.  
  762.     mode.c_lflag |= (ISIG | ICANON | ECHO | ECHOE | ECHOK
  763. #ifdef ECHOCTL
  764.              | ECHOCTL
  765. #endif
  766. #ifdef ECHOKE
  767.              | ECHOKE
  768. #endif
  769.     );
  770. #endif
  771.  
  772.     SET_TTY(STDERR_FILENO, &mode);
  773. }
  774.  
  775. /*
  776.  * Returns a "good" value for the erase character.  This is loosely based on
  777.  * the BSD4.4 logic.
  778.  */
  779. #ifdef TERMIOS
  780. static int
  781. default_erase(void)
  782. {
  783.     int result;
  784.  
  785.     if (over_strike
  786.     && key_backspace != 0
  787.     && strlen(key_backspace) == 1)
  788.     result = key_backspace[0];
  789.     else
  790.     result = CERASE;
  791.  
  792.     return result;
  793. }
  794. #endif
  795.  
  796. /*
  797.  * Update the values of the erase, interrupt, and kill characters in 'mode'.
  798.  *
  799.  * SVr4 tset (e.g., Solaris 2.5) only modifies the intr, quit or erase
  800.  * characters if they're unset, or if we specify them as options.  This differs
  801.  * from BSD 4.4 tset, which always sets erase.
  802.  */
  803. static void
  804. set_control_chars(void)
  805. {
  806. #ifdef TERMIOS
  807.     if (mode.c_cc[VERASE] == 0 || terasechar >= 0)
  808.     mode.c_cc[VERASE] = terasechar >= 0 ? terasechar : default_erase();
  809.  
  810.     if (mode.c_cc[VINTR] == 0 || intrchar >= 0)
  811.     mode.c_cc[VINTR] = intrchar >= 0 ? intrchar : CINTR;
  812.  
  813.     if (mode.c_cc[VKILL] == 0 || tkillchar >= 0)
  814.     mode.c_cc[VKILL] = tkillchar >= 0 ? tkillchar : CKILL;
  815. #endif
  816. }
  817.  
  818. /*
  819.  * Set up various conversions in 'mode', including parity, tabs, returns,
  820.  * echo, and case, according to the termcap entry.  If the program we're
  821.  * running was named with a leading upper-case character, map external
  822.  * uppercase to internal lowercase.
  823.  */
  824. static void
  825. set_conversions(void)
  826. {
  827. #ifdef __OBSOLETE__
  828.     /*
  829.      * Conversion logic for some *really* ancient terminal glitches,
  830.      * not supported in terminfo.  Left here for succeeding generations
  831.      * to marvel at.
  832.      */
  833.     if (tgetflag("UC")) {
  834. #ifdef IUCLC
  835.     mode.c_iflag |= IUCLC;
  836.     mode.c_oflag |= OLCUC;
  837. #endif
  838.     } else if (tgetflag("LC")) {
  839. #ifdef IUCLC
  840.     mode.c_iflag &= ~IUCLC;
  841.     mode.c_oflag &= ~OLCUC;
  842. #endif
  843.     }
  844.     mode.c_iflag &= ~(PARMRK | INPCK);
  845.     mode.c_lflag |= ICANON;
  846.     if (tgetflag("EP")) {
  847.     mode.c_cflag |= PARENB;
  848.     mode.c_cflag &= ~PARODD;
  849.     }
  850.     if (tgetflag("OP")) {
  851.     mode.c_cflag |= PARENB;
  852.     mode.c_cflag |= PARODD;
  853.     }
  854. #endif /* __OBSOLETE__ */
  855.  
  856. #ifdef TERMIOS
  857. #ifdef ONLCR
  858.     mode.c_oflag |= ONLCR;
  859. #endif
  860.     mode.c_iflag |= ICRNL;
  861.     mode.c_lflag |= ECHO;
  862. #ifdef OXTABS
  863.     mode.c_oflag |= OXTABS;
  864. #endif /* OXTABS */
  865.  
  866.     /* test used to be tgetflag("NL") */
  867.     if (newline != (char *) 0 && newline[0] == '\n' && !newline[1]) {
  868.     /* Newline, not linefeed. */
  869. #ifdef ONLCR
  870.     mode.c_oflag &= ~ONLCR;
  871. #endif
  872.     mode.c_iflag &= ~ICRNL;
  873.     }
  874. #ifdef __OBSOLETE__
  875.     if (tgetflag("HD"))        /* Half duplex. */
  876.     mode.c_lflag &= ~ECHO;
  877. #endif /* __OBSOLETE__ */
  878. #ifdef OXTABS
  879.     /* test used to be tgetflag("pt") */
  880.     if (has_hardware_tabs)    /* Print tabs. */
  881.     mode.c_oflag &= ~OXTABS;
  882. #endif /* OXTABS */
  883.     mode.c_lflag |= (ECHOE | ECHOK);
  884. #endif
  885. }
  886.  
  887. /* Output startup string. */
  888. static void
  889. set_init(void)
  890. {
  891.     char *p;
  892.     bool settle;
  893.  
  894. #ifdef __OBSOLETE__
  895.     if (pad_char != (char *) 0)    /* Get/set pad character. */
  896.     PC = pad_char[0];
  897. #endif /* OBSOLETE */
  898.  
  899. #ifdef TAB3
  900.     if (oldmode.c_oflag & (TAB3 | ONLCR | OCRNL | ONLRET)) {
  901.     oldmode.c_oflag &= (TAB3 | ONLCR | OCRNL | ONLRET);
  902.     SET_TTY(STDERR_FILENO, &oldmode);
  903.     }
  904. #endif
  905.     settle = set_tabs();
  906.  
  907.     if (isreset) {
  908.     if ((p = reset_1string) != 0) {
  909.         tputs(p, 0, outc);
  910.         settle = TRUE;
  911.     }
  912.     if ((p = reset_2string) != 0) {
  913.         tputs(p, 0, outc);
  914.         settle = TRUE;
  915.     }
  916.     /* What about rf, rs3, as per terminfo man page? */
  917.     /* also might be nice to send rmacs, rmul, rmm */
  918.     if ((p = reset_file) != 0
  919.         || (p = init_file) != 0) {
  920.         cat(p);
  921.         settle = TRUE;
  922.     }
  923.     }
  924.  
  925.     if (settle) {
  926.     (void) putc('\r', stderr);
  927.     (void) fflush(stderr);
  928.     (void) napms(1000);    /* Settle the terminal. */
  929.     }
  930. }
  931.  
  932. /*
  933.  * Set the hardware tabs on the terminal, using the ct (clear all tabs),
  934.  * st (set one tab) and ch (horizontal cursor addressing) capabilities.
  935.  * This is done before if and is, so they can patch in case we blow this.
  936.  * Return TRUE if we set any tab stops, FALSE if not.
  937.  */
  938. static bool
  939. set_tabs()
  940. {
  941.     if (set_tab && clear_all_tabs) {
  942.     int c;
  943.  
  944.     (void) putc('\r', stderr);    /* Force to left margin. */
  945.     tputs(clear_all_tabs, 0, outc);
  946.  
  947.     for (c = 8; c < tcolumns; c += 8) {
  948.         /* Get to the right column.  In BSD tset, this
  949.          * used to try a bunch of half-clever things
  950.          * with cup and hpa, for an average saving of
  951.          * somewhat less than two character times per
  952.          * tab stop, less that .01 sec at 2400cps. We
  953.          * lost all this cruft because it seemed to be
  954.          * introducing some odd bugs.
  955.          * ----------12345678----------- */
  956.         (void) fputs("        ", stderr);
  957.         tputs(set_tab, 0, outc);
  958.     }
  959.     putc('\r', stderr);
  960.     return (TRUE);
  961.     }
  962.     return (FALSE);
  963. }
  964.  
  965. /**************************************************************************
  966.  *
  967.  * Main sequence
  968.  *
  969.  **************************************************************************/
  970.  
  971. /*
  972.  * Tell the user if a control key has been changed from the default value.
  973.  */
  974. #ifdef TERMIOS
  975. static void
  976. report(const char *name, int which, unsigned def)
  977. {
  978.     unsigned older, newer;
  979.     char *p;
  980.  
  981.     newer = mode.c_cc[which];
  982.     older = oldmode.c_cc[which];
  983.  
  984.     if (older == newer && older == def)
  985.     return;
  986.  
  987.     (void) fprintf(stderr, "%s %s ", name, older == newer ? "is" : "set to");
  988.  
  989.     /*
  990.      * Check 'delete' before 'backspace', since the key_backspace value
  991.      * is ambiguous.
  992.      */
  993.     if (newer == 0177)
  994.     (void) fprintf(stderr, "delete.\n");
  995.     else if ((p = key_backspace) != 0
  996.          && newer == (unsigned char) p[0]
  997.          && p[1] == '\0')
  998.     (void) fprintf(stderr, "backspace.\n");
  999.     else if (newer < 040) {
  1000.     newer ^= 0100;
  1001.     (void) fprintf(stderr, "control-%c (^%c).\n", newer, newer);
  1002.     } else
  1003.     (void) fprintf(stderr, "%c.\n", newer);
  1004. }
  1005. #endif
  1006.  
  1007. /*
  1008.  * Convert the obsolete argument forms into something that getopt can handle.
  1009.  * This means that -e, -i and -k get default arguments supplied for them.
  1010.  */
  1011. static void
  1012. obsolete(char **argv)
  1013. {
  1014.     for (; *argv; ++argv) {
  1015.     char *parm = argv[0];
  1016.  
  1017.     if (parm[0] == '-' && parm[1] == '\0') {
  1018.         argv[0] = strdup("-q");
  1019.         continue;
  1020.     }
  1021.  
  1022.     if ((parm[0] != '-')
  1023.         || (argv[1] && argv[1][0] != '-')
  1024.         || (parm[1] != 'e' && parm[1] != 'i' && parm[1] != 'k')
  1025.         || (parm[2] != '\0'))
  1026.         continue;
  1027.     switch (argv[0][1]) {
  1028.     case 'e':
  1029.         argv[0] = strdup("-e^H");
  1030.         break;
  1031.     case 'i':
  1032.         argv[0] = strdup("-i^C");
  1033.         break;
  1034.     case 'k':
  1035.         argv[0] = strdup("-k^U");
  1036.         break;
  1037.     }
  1038.     }
  1039. }
  1040.  
  1041. static void
  1042. usage(const char *pname)
  1043. {
  1044.     (void) fprintf(stderr,
  1045.            "usage: %s [-IQVrs] [-] [-e ch] [-i ch] [-k ch] [-m mapping] [terminal]", pname);
  1046.     exit_error();
  1047.     /* NOTREACHED */
  1048. }
  1049.  
  1050. static char
  1051. arg_to_char(void)
  1052. {
  1053.     return (optarg[0] == '^' && optarg[1] != '\0')
  1054.     ? ((optarg[1] == '?') ? '\177' : CTRL(optarg[1]))
  1055.     : optarg[0];
  1056. }
  1057.  
  1058. int
  1059. main(int argc, char **argv)
  1060. {
  1061. #if defined(TIOCGWINSZ) && defined(TIOCSWINSZ)
  1062.     struct winsize win;
  1063. #endif
  1064.     int ch, noinit, noset, quiet, Sflag, sflag, showterm;
  1065.     const char *p;
  1066.     const char *ttype;
  1067.  
  1068.     if (GET_TTY(STDERR_FILENO, &mode) < 0)
  1069.     failed("standard error");
  1070.     can_restore = TRUE;
  1071.     original = oldmode = mode;
  1072. #ifdef TERMIOS
  1073.     ospeed = cfgetospeed(&mode);
  1074. #else
  1075.     ospeed = mode.sg_ospeed;
  1076. #endif
  1077.  
  1078.     p = _nc_rootname(*argv);
  1079.     if (!strcmp(p, PROG_RESET)) {
  1080.     isreset = TRUE;
  1081.     reset_mode();
  1082.     }
  1083.  
  1084.     obsolete(argv);
  1085.     noinit = noset = quiet = Sflag = sflag = showterm = 0;
  1086.     while ((ch = getopt(argc, argv, "a:d:e:Ii:k:m:np:qQSrsV")) != EOF) {
  1087.     switch (ch) {
  1088.     case 'q':        /* display term only */
  1089.         noset = 1;
  1090.         break;
  1091.     case 'a':        /* OBSOLETE: map identifier to type */
  1092.         add_mapping("arpanet", optarg);
  1093.         break;
  1094.     case 'd':        /* OBSOLETE: map identifier to type */
  1095.         add_mapping("dialup", optarg);
  1096.         break;
  1097.     case 'e':        /* erase character */
  1098.         terasechar = arg_to_char();
  1099.         break;
  1100.     case 'I':        /* no initialization strings */
  1101.         noinit = 1;
  1102.         break;
  1103.     case 'i':        /* interrupt character */
  1104.         intrchar = arg_to_char();
  1105.         break;
  1106.     case 'k':        /* kill character */
  1107.         tkillchar = arg_to_char();
  1108.         break;
  1109.     case 'm':        /* map identifier to type */
  1110.         add_mapping(0, optarg);
  1111.         break;
  1112.     case 'n':        /* OBSOLETE: set new tty driver */
  1113.         break;
  1114.     case 'p':        /* OBSOLETE: map identifier to type */
  1115.         add_mapping("plugboard", optarg);
  1116.         break;
  1117.     case 'Q':        /* don't output control key settings */
  1118.         quiet = 1;
  1119.         break;
  1120.     case 'S':        /* OBSOLETE: output TERM & TERMCAP */
  1121.         Sflag = 1;
  1122.         break;
  1123.     case 'r':        /* display term on stderr */
  1124.         showterm = 1;
  1125.         break;
  1126.     case 's':        /* output TERM set command */
  1127.         sflag = 1;
  1128.         break;
  1129.     case 'V':
  1130.         puts(curses_version());
  1131.         return EXIT_SUCCESS;
  1132.     case '?':
  1133.     default:
  1134.         usage(*argv);
  1135.     }
  1136.     }
  1137.     argc -= optind;
  1138.     argv += optind;
  1139.  
  1140.     if (argc > 1)
  1141.     usage(*argv);
  1142.  
  1143.     ttype = get_termcap_entry(*argv);
  1144.  
  1145.     if (!noset) {
  1146.     tcolumns = columns;
  1147.     tlines = lines;
  1148.  
  1149. #if defined(TIOCGWINSZ) && defined(TIOCSWINSZ)
  1150.     /* Set window size */
  1151.     (void) ioctl(STDERR_FILENO, TIOCGWINSZ, &win);
  1152.     if (win.ws_row == 0 && win.ws_col == 0 &&
  1153.         tlines > 0 && tcolumns > 0) {
  1154.         win.ws_row = tlines;
  1155.         win.ws_col = tcolumns;
  1156.         (void) ioctl(STDERR_FILENO, TIOCSWINSZ, &win);
  1157.     }
  1158. #endif
  1159.     set_control_chars();
  1160.     set_conversions();
  1161.  
  1162.     if (!noinit)
  1163.         set_init();
  1164.  
  1165.     /* Set the modes if they've changed. */
  1166.     if (memcmp(&mode, &oldmode, sizeof(mode))) {
  1167.         SET_TTY(STDERR_FILENO, &mode);
  1168.     }
  1169.     }
  1170.  
  1171.     /* Get the terminal name from the entry. */
  1172.     ttype = _nc_first_name(cur_term->type.term_names);
  1173.  
  1174.     if (noset)
  1175.     (void) printf("%s\n", ttype);
  1176.     else {
  1177.     if (showterm)
  1178.         (void) fprintf(stderr, "Terminal type is %s.\n", ttype);
  1179.     /*
  1180.      * If erase, kill and interrupt characters could have been
  1181.      * modified and not -Q, display the changes.
  1182.      */
  1183. #ifdef TERMIOS
  1184.     if (!quiet) {
  1185.         report("Erase", VERASE, CERASE);
  1186.         report("Kill", VKILL, CINTR);
  1187.         report("Interrupt", VINTR, CKILL);
  1188.     }
  1189. #endif
  1190.     }
  1191.  
  1192.     if (Sflag)
  1193.     err("The -S option is not supported under terminfo.");
  1194.  
  1195.     if (sflag) {
  1196.     /*
  1197.      * Figure out what shell we're using.  A hack, we look for an
  1198.      * environmental variable SHELL ending in "csh".
  1199.      */
  1200.     if ((p = getenv("SHELL")) != 0
  1201.         && !strcmp(p + strlen(p) - 3, "csh"))
  1202.         p = "set noglob;\nsetenv TERM %s;\nunset noglob;\n";
  1203.     else
  1204.         p = "TERM=%s;\n";
  1205.     (void) printf(p, ttype);
  1206.     }
  1207.  
  1208.     return EXIT_SUCCESS;
  1209. }
  1210.  
  1211. /* tset.c ends here */
  1212.